package cn.yunyichina.provider.pay.wechat.service.impl;

import cn.yunyichina.provider.iface.entity.common.ResponseObject;
import cn.yunyichina.provider.iface.entity.wechat.WechatMedicalRefundRequest;
import cn.yunyichina.provider.iface.entity.wechat.WechatMedicalRefundResponse;
import cn.yunyichina.provider.pay.wechat.common.XMLUtil;
import cn.yunyichina.provider.pay.wechat.config.Wechat;
import cn.yunyichina.provider.pay.wechat.constant.ResponseEnum;
import cn.yunyichina.provider.pay.wechat.entity.WechatMedicalTradeRefundResponse;
import cn.yunyichina.provider.pay.wechat.entity.common.WechatCommonResponse;
import cn.yunyichina.provider.pay.wechat.entity.common.WechatTradeRefundRequest;
import cn.yunyichina.provider.pay.wechat.entity.common.WechatTradeRefundResponse;
import cn.yunyichina.provider.pay.wechat.service.BaseRefundService;
import cn.yunyichina.provider.pay.wechat.service.WechatRefundService;
import cn.yunyichina.utils.commons.DateUtils;
import cn.yunyichina.utils.commons.HttpUtil;
import cn.yunyichina.utils.convert.JsonUtils;
import cn.yunyichina.utils.security.SignUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.Calendar;
import java.util.Map;

/**
 * Created by Lullaby on 2016/10/27.
 */
@Service
public class WechatRefundServiceImpl extends BaseRefundService implements WechatRefundService {

    private static final Logger logger = LoggerFactory.getLogger(WechatRefundServiceImpl.class);

    public ResponseObject refundWechat(String json) {
        logger.info("WechatRefundServiceImpl.refundWechat.json -> {}", json);

        ResponseObject response = new ResponseObject();

        try {
            WechatTradeRefundRequest refundRequest = JsonUtils.parseObject(json, WechatTradeRefundRequest.class);

            String apiSecret = refundRequest.getApiSecret();
            refundRequest.setApiSecret(null);
            refundRequest.setSign(SignUtil.wechatPaySign(JsonUtils.parseObject(refundRequest, Map.class), apiSecret));

            String xml = XMLUtil.buildMapXML(JsonUtils.parseObject(refundRequest, Map.class));
            logger.info("WechatRefundServiceImpl.refundWechat.xml -> {}", xml);

            String mchId = refundRequest.getMchId();
            String certPath = "/cert/" + mchId + ".p12";
            String result = HttpUtil.doWechatSslPost(this.getConfig(Wechat.WECHAT_PAY_PAY_REFUND), xml, mchId, certPath);
            logger.info("WechatRefundServiceImpl.refundWechat.result -> {}", result);

            Map<String, String> resultMap = XMLUtil.xmlToMap(result);
            logger.info("WechatRefundServiceImpl.refundWechat.resultMap -> {}", JsonUtils.toJsonString(resultMap));

            WechatTradeRefundResponse refundResponse = JsonUtils.parseObject(resultMap, WechatTradeRefundResponse.class);
            logger.info("WechatRefundServiceImpl.refundWechat.refundResponse -> {}", JsonUtils.toJsonString(refundResponse));

            if (refundResponse.isReturnCodeSuccess()) {
                if (SignUtil.validateWechatPaySign(resultMap, apiSecret)) {
                    if (refundResponse.isResultCodeSuccess()) {
                        logger.info("WechatRefundServiceImpl.refundWechat -> SUCCESS");
                        response.setResultObject(buildWechatRefundResponse(refundResponse));
                    } else {
                        response.setResultCodeAndMessageAndResult(
                                ResponseEnum.WECHAT_REFUND_TRADE_FAIL.getCode(),
                                ResponseEnum.WECHAT_REFUND_TRADE_FAIL.getMessage(),
                                getWechatErrCodeAndDes(JsonUtils.parseObject(resultMap, WechatCommonResponse.class))
                        );
                    }
                } else {
                    response.setResultCodeAndMessage(
                            ResponseEnum.WECHAT_INVALID_SIGN.getCode(),
                            ResponseEnum.WECHAT_INVALID_SIGN.getMessage()
                    );
                }
            } else {
                response.setResultCodeAndMessageAndResult(
                        ResponseEnum.WECHAT_REFUND_FAIL.getCode(),
                        ResponseEnum.WECHAT_REFUND_FAIL.getMessage(),
                        getWechatReturnCodeAndMsg(JsonUtils.parseObject(resultMap, WechatCommonResponse.class))
                );
            }
        } catch (Exception e) {
            logger.error("WechatRefundServiceImpl.refundWechat.exception", e);
            response.setResultCodeAndMessage(
                    ResponseEnum.WECHAT_REFUND_EXCEPTION.getCode(),
                    ResponseEnum.WECHAT_REFUND_EXCEPTION.getMessage()
            );
        }

        return response;
    }

    public WechatMedicalRefundResponse wechatMedicalRefund(WechatMedicalRefundRequest request) {
        logger.info("WechatRefundServiceImpl.wechatMedicalRefund.json -> {}", JsonUtils.toJsonString(request));

        WechatMedicalRefundResponse response = new WechatMedicalRefundResponse();

        try {
            Map<String, String> params = JsonUtils.parseObject(request, Map.class);
            logger.info("WechatRefundServiceImpl.wechatMedicalRefund.params -> {}", JsonUtils.toJsonString(params));

            String accessToken = params.get("access_token");
            String apiSecret = params.get("api_secret");

            params.remove("access_token");
            params.remove("api_secret");

            params.put("sign", SignUtil.wechatPaySign(params, apiSecret));

            String xml = XMLUtil.buildMapXML(params);
            logger.info("WechatRefundServiceImpl.wechatMedicalRefund.xml -> {}", xml);

            String requestUrl = String.format(this.getConfig(Wechat.WECHAT_MEDICAL_REFUND), accessToken);
            logger.info("WechatRefundServiceImpl.wechatMedicalRefund.requestUrl -> {}", requestUrl);

            String result = HttpUtil.post(xml, requestUrl);
            logger.info("WechatRefundServiceImpl.wechatMedicalRefund.result -> {}", result);

            Map<String, String> resultMap = XMLUtil.xmlToMap(result);
            logger.info("WechatRefundServiceImpl.wechatMedicalRefund.resultMap -> {}", JsonUtils.toJsonString(resultMap));

            WechatMedicalTradeRefundResponse medicalTradeRefundResponse = JsonUtils.parseObject(resultMap, WechatMedicalTradeRefundResponse.class);
            logger.info("WechatRefundServiceImpl.wechatMedicalRefund.medicalTradeRefundResponse -> {}", JsonUtils.toJsonString(medicalTradeRefundResponse));

            if (medicalTradeRefundResponse.isReturnCodeSuccess() && medicalTradeRefundResponse.isResultCodeSuccess()) {
                if (SignUtil.validateWechatPaySign(resultMap, apiSecret)) {
                    response.setSuccess(true);
                    response.setRefundAmount(
                            medicalTradeRefundResponse.getCashRefundFee() == null ?
                                    medicalTradeRefundResponse.getInsuranceRefundFee() == null ?
                                            medicalTradeRefundResponse.getTotalFee() == null ?
                                                    "0" :
                                                    medicalTradeRefundResponse.getTotalFee() :
                                            medicalTradeRefundResponse.getInsuranceRefundFee() :
                                    medicalTradeRefundResponse.getCashRefundFee()
                    );
                    response.setPlatformOrderNo(request.getHospOutTradeNo());
                    response.setPlatformSerialNumber(request.getHospOutRefundNo());
                    response.setRefundTime(DateUtils.dateToString(Calendar.getInstance().getTime()));
                    response.setPayTransactionId(medicalTradeRefundResponse.getMedRefundId());

                    return response;
                }
                logger.info("WechatRefundServiceImpl.wechatMedicalRefund check sign failed ");
            }

            response.setSuccess(false);
        } catch (Exception e) {
            response.setSuccess(false);
            logger.info("WechatRefundServiceImpl.wechatMedicalRefund.Exception", e);
        }

        return response;
    }

}
